CDKを使用してVPCを作成する
今回作成するリソース
今回は2個のAZにまたがってVPCを定義します。
各AZにはpublic
、private
、isolated
の三つのサブネットを用意します。
図にすると以下のようになります。
public
サブネット
public
サブネットではインターネットゲートウェイへのルーティングが設定されており、直接インターネットとのやり取りが可能です。ElasticIPを割り振ることでEC2インスタンス、ELB、NATゲートウェイが外部からの通信を受け入れることが可能です。
private
サブネット
private
サブネットでは外部との通信はNATゲートウェイを介して行われます。インターネットゲートウェイへのルーティングがなく、基本的にはインターネットからのアクセスはありません。なので、public
サブネットを介して通信が行われることがあります。
isolated
サブネット
isolated
サブネットはローカルとの通信しかできません。ここではpublic
、private
との相互通信が可能です。
DBなど外部への通信が不要で、ローカルなマシンとののみ通信が必要なリソースがしばしば設置されます。
準備
CDKの準備
まずはCDKの準備をします。 今回はPythonを使用します。
PythonのCDKのパッケージのバージョンはaws-cdk-lib==2.9.0
です。
$ npm init $ npm install aws-cdk $ mkdir three-tier $ cd three-tier $ npx cdk init --language python
つぎにCDKで使用するPythonパッケージをインストールします。
CDKでPythonを使用する場合はvenv
が用意されているので、それを使うと便利です。
$ source .venv/bin/activate $ pip3 install -r requirements.txt
以降では常にsource .venv/bin/activate
を行ったあとのvenv
の環境で作業を行います。
コードの準備
まずはスタックを定義します。
from aws_cdk import ( Stack, aws_ec2 as ec2 ) from constructs import Construct VCP_CIDR = '192.168.0.0/16' class ThreeTierStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) self.vpc = ec2.Vpc( self, 'three-tier', cidr=VCP_CIDR, max_azs=2, subnet_configuration=[ ec2.SubnetConfiguration( name='public', subnet_type=ec2.SubnetType.PUBLIC ), ec2.SubnetConfiguration( name='private', subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT ), ec2.SubnetConfiguration( name='isolated', subnet_type=ec2.SubnetType.PRIVATE_ISOLATED ), ] )
ここではVPCの定義を行っています。ec2.Vpc
はリソースを作成するためのハイレベルなインターフェイスで、少ない手順でVPCで使用するインターネットゲートウェイや、NATゲートウェイ、サブネットなどの設定ができます。
ここではmax_azs
を2とすることで以下でサブネットが各AZ毎に作成されます。
subnet_configuration
ではサブネットの設定を行っています。CIDRの分割はVPCに設定されたCIDRから自動で行ってくれます。このときsubnet_type
を指定することで先述のpublic
、private
、isolated
の設定ができます。
一緒にapp.py
も書き換えます。
#!/usr/bin/env python3 import os import aws_cdk as cdk from vpc.vpc_stack import ThreeTierStack app = cdk.App() vpc_stack = ThreeTierStack(app, "ThreeTierVPC") cdk.Tags.of(vpc_stack).add('Project', 'three-tier') app.synth()
ここではStackにタグをつけています。こうすることで、スタック内で作成されるリソースにタグが自動てつけられます。
タグのキーはProject
で値はthree-tier
です。
デプロイする
最初にブートストラップを行い初期化を行ったのち、デプロイします。 デプロイには10分ぐらいの時間がかかります。
$ npx cdk bootstrap $ npx cdk deploy
結果を確認する
サブネットのAZとCIDRを確認する
まずはサブネットの一覧を確認してみます。(見やすいように適宜開業を入れてあります。)
$ aws ec2 describe-subnets \ --filter "Name=tag:Project,Values=three-tier" \ --query 'Subnets[].[Tags[?Key==`Name`].Value,[AvailabilityZone,CidrBlock]] | reverse(sort_by(@, &[0][0]))' \ --output text ThreeTierVPC/three-tier/publicSubnet2 ap-northeast-1c 192.168.32.0/19 ThreeTierVPC/three-tier/publicSubnet1 ap-northeast-1a 192.168.0.0/19 ThreeTierVPC/three-tier/privateSubnet2 ap-northeast-1c 192.168.96.0/19 ThreeTierVPC/three-tier/privateSubnet1 ap-northeast-1a 192.168.64.0/19 ThreeTierVPC/three-tier/isolatedSubnet2 ap-northeast-1c 192.168.160.0/19 ThreeTierVPC/three-tier/isolatedSubnet1 ap-northeast-1a 192.168.128.0/19
ap-northeast-1a
とap-northeast-1a
にそれぞれサブネットが作られています。
ルートテーブルの確認
続いてルートテーブルの設定を見てみます。
$ aws ec2 describe-route-tables \ --filter "Name=tag:Project,Values=three-tier"\ --query 'RouteTables[].[Tags[?Key==`Name`].Value,Routes[].[DestinationCidrBlock,GatewayId,NatGatewayId]] | reverse(sort_by(@, &[0][0]))' \ --output text ThreeTierVPC/three-tier/publicSubnet2 192.168.0.0/16 local None 0.0.0.0/0 igw-XXXXXX None ThreeTierVPC/three-tier/publicSubnet1 192.168.0.0/16 local None 0.0.0.0/0 igw-XXXXXX None ThreeTierVPC/three-tier/privateSubnet2 192.168.0.0/16 local None 0.0.0.0/0 None nat-XXXXXX ThreeTierVPC/three-tier/privateSubnet1 192.168.0.0/16 local None 0.0.0.0/0 None nat-YYYYYY ThreeTierVPC/three-tier/isolatedSubnet2 192.168.0.0/16 local None ThreeTierVPC/three-tier/isolatedSubnet1 192.168.0.0/16 local None
public
サブネットにはインターネットゲートウェイ(igw-XXXXXX)へのルーティングが設定されています。
同様にprivate
サブネットではNATゲートウェイ(nat-XXXXXX、nat-YYYYYY)へのルーティングが定義されています。
isolated
サブネットではローカル以外のルーティングが定義されていません。
また、private
サブネットではサブネット毎に異なったNATゲートウェイが指定されています。
これは各AZのpublic
サブネットに展開されたNATゲートウェイを参照しているためです。
つまりは、同一AZのNATゲートウェイを使用するようになっています。
削除する
最後に削除して終わります。
$ npx cdk destroy
最後に
CDKを使用することで簡単に複雑な構造のVPCを定義することができました。 細かい設定をしない場合はこのようにハイレベルのインターフェイスを使用することで手順を省くことができます。